﻿Imports System.ComponentModel

Public Class frmLedgerUnPost

    Private m_workPeriodList As List(Of ClsTWorkPeriod) = New List(Of ClsTWorkPeriod)()
    Private m_curPeriod As ClsTWorkPeriod = Nothing
    Private m_rowIndex As Integer = -1
    Private m_working As Boolean = False
    Private m_unPostOk As Boolean = False
    Private m_unSettleOk As Boolean = False

    Private Delegate Sub UnPostDone(ByVal wp As ClsTWorkPeriod)
    Private m_UnPostDoneSub As UnPostDone = New UnPostDone(AddressOf UnpostHandle)

    '窗体调用主窗体显示过程
    Private Delegate Sub SetMainShowInfo(ByVal info As String)
    Private m_showInfoInMainForm As SetMainShowInfo = New SetMainShowInfo(AddressOf SetMessageToMianForm)

    ''' <summary>
    ''' 在MDI主窗体上显示信息
    ''' </summary>
    ''' <param name="info"></param>
    Private Sub SetMessageToMianForm(ByVal info As String)
        sysFrmMdiMain.SetNotifyText(info)
    End Sub

    Private Sub frmLedgerUnPost_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '加载期间数据
        Me.btnUnPost.Enabled = False
        Me.btnUnSettle.Enabled = False
        Me.btnClose.Enabled = False
        Dim tmpWPDb As ClsTWorkPeriodDbAccess = New ClsTWorkPeriodDbAccess(sysUserDataConnectionString)
        '取出当前年度的全部期间过账及结账数据
        m_workPeriodList = tmpWPDb.GetWorkPeriodByYear(sysCurrentLedgerSetting.LedgerWorkYear.Substring(0, 4))
        '初始化列表数据
        InitialListView()

        m_working = False

        '准备按钮状态
        CheckButtonsState()

    End Sub

    ''' <summary>
    ''' 检查按钮状态
    ''' </summary>
    Private Sub CheckButtonsState()
        If m_rowIndex <> -1 Then
            '有选择行，则进一步判断是否可以反过账或反结账。
            If m_curPeriod.Settled Then
                Me.btnUnSettle.Enabled = True
                '已结账，则必须先反结，才能反过
                Me.btnUnPost.Enabled = False
            Else
                Me.btnUnSettle.Enabled = False
                '如果没有结账，则查看是否可以反过
                If m_curPeriod.Posted Then
                    Me.btnUnPost.Enabled = True
                Else
                    Me.btnUnPost.Enabled = False
                End If
            End If

        End If

        Me.btnClose.Enabled = (Not m_working)

    End Sub

    Private Sub InitialListView()
        '初始化表头
        InitialListViewHeader()
        '初始化列表数据
        LoadDataToListView()
    End Sub

    ''' <summary>
    ''' 将数据加载到列表集合中
    ''' </summary>
    Private Sub LoadDataToListView()
        '判断当前是否有期间数据
        If m_workPeriodList.Count < 1 Then
            Return
        End If

        '循环加入列表
        For Each wp As ClsTWorkPeriod In m_workPeriodList
            '加入一行记录到集合中
            AddClassToListView(wp)
        Next

        '初始化选择
        m_rowIndex = -1
        m_curPeriod = Nothing


    End Sub

    ''' <summary>
    ''' 将一个会计期间数据加入到窗体列表中
    ''' </summary>
    ''' <param name="wp"></param>
    Private Sub AddClassToListView(ByVal wp As ClsTWorkPeriod)
        '判断参数是否为空
        If wp Is Nothing Then
            Return
        End If

        '将一个 账套变量 加入到列表中
        Dim tmpItem As ListViewItem = New ListViewItem(wp.WorkPeriod)

        tmpItem.SubItems.Add(wp.VoucherCount.ToString())
        tmpItem.SubItems.Add(IIf(wp.Posted, "是", "否"))
        tmpItem.SubItems.Add(IIf(wp.Settled, "是", "否"))

        Me.lstWorkPeriod.Items.Add(tmpItem)

    End Sub

    ''' <summary>
    ''' 初始化列表表头
    ''' </summary>
    Private Sub InitialListViewHeader()
        '初始化列表标题
        Dim header1 As ColumnHeader = New ColumnHeader()
        header1.Text = "会计期间"
        header1.Width = 80
        header1.TextAlign = HorizontalAlignment.Center
        header1.Name = "hWorkPeriod"

        Dim header2 As ColumnHeader = New ColumnHeader()
        With header2
            .Text = "凭证数量"
            .Width = 60
            .TextAlign = HorizontalAlignment.Left
            .Name = "hVoucherCount"

        End With

        Dim header3 As ColumnHeader = New ColumnHeader()
        With header3
            .Text = "过账"
            .Width = 50
            .TextAlign = HorizontalAlignment.Left
            .Name = "hPosted"
            '.AutoResize = True
        End With

        Dim header4 As ColumnHeader = New ColumnHeader()
        With header4
            .Text = "结账"
            .Width = 50
            .TextAlign = HorizontalAlignment.Left
            .Name = "hSettled"
        End With


        With Me.lstWorkPeriod
            .FullRowSelect = True '行选择模式
            .MultiSelect = True '不允许 多行选择
            .View = View.Details '视图选项：详细模式
            '.Width = Me.FlowLayoutPanel1.Width  '宽度占满窗体
            .HeaderStyle = ColumnHeaderStyle.Nonclickable '标题不可点击
            .Columns.Add(header1)
            .Columns.Add(header2)
            .Columns.Add(header3)
            .Columns.Add(header4)
            '根据内容调整列宽
            'ListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); 
            'ListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
        End With
    End Sub

    Private Sub lstWorkPeriod_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstWorkPeriod.SelectedIndexChanged
        '判断当前是否选择了某一行
        '取出当前选择行
        Dim selItems As ListView.SelectedListViewItemCollection = Me.lstWorkPeriod.SelectedItems

        If selItems.Count < 1 Then
            Return
        End If

        m_rowIndex = selItems.Item(0).Index
        m_curPeriod = m_workPeriodList.Item(m_rowIndex)


        CheckButtonsState()
    End Sub

    ''' <summary>
    ''' 将选定的一个期间进行反过账
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub btnUnPost_Click(sender As Object, e As EventArgs) Handles btnUnPost.Click
        '判断当前是否选择了一行
        If m_curPeriod Is Nothing Then
            Return
        End If

        '取出当前期间，反过账
        Dim t As Threading.Thread = New Threading.Thread(AddressOf UnPostWorkPeriod)
        t.Start(m_curPeriod)
    End Sub

    ''' <summary>
    ''' 反过账会计期间：从指定的期间开始。
    ''' </summary>
    ''' <param name="wp"></param>
    Private Sub UnPostWorkPeriod(ByVal wp As ClsTWorkPeriod)

        sysFrmMdiMain.Invoke(m_showInfoInMainForm, New Object() {"反过账当前选定的会计期间..."})

        m_working = True

        '取出当前期间所在索引，判断此索引下的各期间是否需要反过账
        For i As Integer = m_workPeriodList.Count - 1 To m_rowIndex
            If m_workPeriodList(i).Posted Then
                If Not UnPostOnePeriod(m_workPeriodList(i).WorkPeriod) Then
                    '出错了，停止
                    MessageBox.Show("反过账指定期间" & m_workPeriodList(i).WorkPeriod & "数据时出错。请稍后再试。", "反过账")
                    m_working = False
                    Return
                End If
            End If
        Next

        m_unPostOk = True
        m_working = False

        '调用委托处理反过账后的事务
        Me.Invoke(m_UnPostDoneSub, New Object() {wp})

        sysFrmMdiMain.Invoke(m_showInfoInMainForm, New Object() {"就绪"})

    End Sub

    ''' <summary>
    ''' 反过账一个会计期间
    ''' </summary>
    ''' <param name="wp"></param>
    ''' <returns></returns>
    Private Function UnPostOnePeriod(ByVal wp As String) As Boolean
        '0、取出数据库对象，开启事务
        Dim tmpAcctSumDb As ClsTAccountSumDbAccess = New ClsTAccountSumDbAccess(sysUserDataConnectionString)
        If Not tmpAcctSumDb.GetConnection().BeginTransaction() Then
            '出错，无法继续
            MessageBox.Show("无法开启数据库事务，反过账停止，请稍后再试。", "反过账")
            '此处需要手工关闭数据库
            tmpAcctSumDb.GetConnection.DbClose()
            Return False
        End If

        '1、清空本月科目汇总
        If tmpAcctSumDb.DeleteAcctSumByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("删除本月科目汇总数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If

        '清空外币科目汇总
        Dim tmpCurrencySumDb As ClsTCurrencySumDbAccess = New ClsTCurrencySumDbAccess(sysUserDataConnectionString)
        If tmpCurrencySumDb.DeletCurrencySumByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("删除本月科目外币汇总数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If

        '清空数量科目汇总
        Dim tmpQuantitySumDb As ClsTQuantitySumDbAccess = New ClsTQuantitySumDbAccess(sysUserDataConnectionString)
        If tmpQuantitySumDb.DeletQuantitySumByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("删除本月科目数量汇总数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If


        '2、清空本月总账数据（包括数量及外币总账）
        Dim tmpGeneralLedgerDb As ClsTGeneralMoneyLedgerDbAccess = New ClsTGeneralMoneyLedgerDbAccess(sysUserDataConnectionString)
        If tmpGeneralLedgerDb.ClearDataByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("清空本月总账数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If
        '清空数量总账
        Dim tmpGeneralQuantityDb As ClsTGeneralQuantityLedgerDbAccess = New ClsTGeneralQuantityLedgerDbAccess(sysUserDataConnectionString)
        If tmpGeneralQuantityDb.ClearDataByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("清空本月数量总账数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If
        '清空外币总账
        Dim tmpGeneralCurrencyDb As ClsTGeneralCurrencyLedgerDbAccess = New ClsTGeneralCurrencyLedgerDbAccess(sysUserDataConnectionString)
        If tmpGeneralCurrencyDb.ClearDataByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("清空本月外向总账数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If

        '3、清空本月余额数据（包括数量余额）
        Dim tmpBalanceMoneyDb As ClsTBalanceMoneyDbAccess = New ClsTBalanceMoneyDbAccess(sysUserDataConnectionString)
        If tmpBalanceMoneyDb.DeleteBalanceByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("删除本月科目余额数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If

        Dim tmpBalanceQuantityDb As ClsTBalanceQuantityDbAccess = New ClsTBalanceQuantityDbAccess(sysUserDataConnectionString)
        If tmpBalanceQuantityDb.DeleteBalanceByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("删除本月科目数量余额数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If

        '4、清空本月三栏账数据
        Dim tmpDetailDb As ClsTDetailReportDbAccess = New ClsTDetailReportDbAccess(sysUserDataConnectionString)
        If tmpDetailDb.DeleteDetailReportByWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("删除本月科目明细账数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If


        '5、清空本会计期间数据
        Dim tmpWorkPeriodDb As ClsTWorkPeriodDbAccess = New ClsTWorkPeriodDbAccess(sysUserDataConnectionString)
        If tmpWorkPeriodDb.DeleteWorkPeriod(wp) = -1 Then
            '出错
            MessageBox.Show("删除本月科目会计期间数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False
        End If

        '6、修改本会计期间凭证过账标记
        Dim tmpVDb As ClsTVoucherDbAccess = New ClsTVoucherDbAccess(sysUserDataConnectionString)
        If tmpVDb.PostAndUnpostVoucherByWorkPeriod(wp, False) = -1 Then
            '出错
            MessageBox.Show("删除本月科目会计期间数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False

        End If

        '9、提交或回滚事务
        If Not tmpAcctSumDb.GetConnection().CompleteTransaction Then
            '出错了，只能回滚
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            '出错
            MessageBox.Show("删除本月科目数量汇总数据时出错。请稍后再试。", "反过账")
            tmpAcctSumDb.GetConnection().RollBackTransaction()

            Return False

        End If

        Return True

    End Function

    ''' <summary>
    ''' 反过账结束后处理窗体对象及控件
    ''' </summary>
    ''' <param name="wp"></param>
    Private Sub UnpostHandle(ByVal wp As ClsTWorkPeriod)

        m_working = False

        '从列表和集合中移除指定期间
        If m_unPostOk Then
            '删除列表和集合数据
            While Me.lstWorkPeriod.Items.Count > m_rowIndex
                Me.lstWorkPeriod.Items.RemoveAt(Me.lstWorkPeriod.Items.Count - 1)
            End While

            m_workPeriodList.RemoveRange(m_rowIndex, m_workPeriodList.Count - m_rowIndex)

            '修改指示器
            m_unPostOk = False

            Return
        End If

        If m_unSettleOk Then
            '修改列表和集合数据内容
            For i As Integer = m_rowIndex To Me.lstWorkPeriod.Items.Count - 1
                Me.lstWorkPeriod.Items(i).SubItems(3).Text = "否"
            Next

            For j As Integer = m_rowIndex To m_workPeriodList.Count - 1
                m_workPeriodList(j).Settled = False
            Next

            '修改指示器
            m_unSettleOk = False

        End If

    End Sub

    Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click
        Me.Close()
    End Sub

    Private Sub frmLedgerUnPost_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
        If m_working Then
            MessageBox.Show("正在处理数据，此时不能退出", "反过账&反结账")
            e.Cancel = True
        End If
    End Sub

    Private Sub btnUnSettle_Click(sender As Object, e As EventArgs) Handles btnUnSettle.Click
        '判断当前是否有选择行
        If m_rowIndex = -1 Then
            Return
        End If

        Dim tmpWPDb As ClsTWorkPeriodDbAccess = New ClsTWorkPeriodDbAccess(sysUserDataConnectionString)
        tmpWPDb.GetConnection().BeginTransaction()

        For i As Integer = m_workPeriodList.Count - 1 To m_rowIndex
            If m_workPeriodList(i).Settled Then
                If tmpWPDb.SettleWorkPeriod(m_workPeriodList(i).WorkPeriod, False) = -1 Then
                    '出错
                    MessageBox.Show("指定会计期间反结账数据时出错。请稍后再试。", "反过账&反结账")
                    tmpWPDb.GetConnection().RollBackTransaction()
                    Return
                End If
            End If
        Next



        '当前会计期间要修改为选定的期间的上一个，如果是1月，则不动
        Dim tmpMonth As Integer
        Dim tmpYear As Integer

        tmpYear = sysCurrentLedgerSetting.LedgerWorkYear.Substring(0, 4)
        Integer.TryParse(m_workPeriodList(m_rowIndex).WorkPeriod.Substring(4), tmpMonth)
        'Integer.TryParse(sysCurrentLedgerSetting.LedgerWorkYear.Substring(4), tmpCurMonth)
        If tmpMonth > 1 Then

            sysCurrentLedgerSetting.LedgerWorkYear = tmpYear & (tmpMonth - 1).ToString("D2")
        Else
            sysCurrentLedgerSetting.LedgerWorkYear = tmpYear & tmpMonth.ToString("D2")
        End If

        '更新当前会计期间
        Dim tmpLedgerSettingDb As ClsTLedgerSettingDbAccess = New ClsTLedgerSettingDbAccess(sysUserDataConnectionString)
        If tmpLedgerSettingDb.UpdateTLedgerSetting(sysCurrentLedgerSetting) = -1 Then
            '出错
            MessageBox.Show("更新当前会计期间数据时出错。请稍后再试。", "反过账&反结账")
            tmpWPDb.GetConnection().RollBackTransaction()
            Return
        End If

        'sysFrmMdiMain.Invoke(m_showInfoInMainForm, New Object() {"同步总账及余额表科目信息..."})
        '更新主窗体的会计期间数据
        sysFrmMdiMain.FreshWorkPeriodText()

        tmpWPDb.GetConnection().CompleteTransaction()
        m_unSettleOk = True

        '委托调用反结账后续事务
        UnpostHandle(m_curPeriod)

        'm_UnPostDoneSub.Invoke(m_curPeriod)

    End Sub
End Class